/*
 * Copyright (c) 2023 Huawei Technologies Co., Ltd.
 * openUBMC is licensed under Mulan PSL v2.
 * You can use this software according to the terms and conditions of the Mulan PSL v2.
 * You may obtain a copy of Mulan PSL v2 at:
 *         http://license.coscl.org.cn/MulanPSL2
 * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
 * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
 * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
 * See the Mulan PSL v2 for more details.
 */

#include "manager.h"

namespace dev {

// 单例实例的静态变量
static std::unique_ptr<device_manager> s_instance = nullptr;
static std::mutex                      s_instance_mutex;

device_manager& device_manager::get_instance() {
    std::lock_guard<std::mutex> lock(s_instance_mutex);
    if (!s_instance) {
        s_instance = std::unique_ptr<device_manager>(new device_manager());
    }
    return *s_instance;
}

device_manager::device_manager() {
    init_factory_maps();
}

void device_manager::init_factory_maps() {
    // 注册chip工厂函数
    m_chip_factories["Pca9545"] = [](mc::mutable_dict& csr_data) -> std::shared_ptr<chip_base> {
        auto ptr = std::make_shared<chip_pca9545>();
        if (ptr && ptr->init(csr_data)) {
            return ptr;
        }
        return nullptr;
    };

    m_chip_factories["Pca9555"] = [](mc::mutable_dict& csr_data) -> std::shared_ptr<chip_base> {
        auto ptr = std::make_shared<chip_pca9555>();
        if (ptr && ptr->init(csr_data)) {
            return ptr;
        }
        return nullptr;
    };
    m_chip_factories["Chip"] = [](mc::mutable_dict& csr_data) -> std::shared_ptr<chip_base> {
        auto ptr = std::make_shared<chip_base>();
        if (ptr && ptr->init(csr_data)) {
            return ptr;
        }
        return nullptr;
    };

    m_chip_factories["Lm75"] = [](mc::mutable_dict& csr_data) -> std::shared_ptr<chip_base> {
        auto ptr = std::make_shared<chip_lm75>();
        if (ptr && ptr->init(csr_data)) {
            return ptr;
        }
        return nullptr;
    };

    m_chip_factories["Ads78"] = [](mc::mutable_dict& csr_data) -> std::shared_ptr<chip_base> {
        auto ptr = std::make_shared<chip_ads78>();
        if (ptr && ptr->init(csr_data)) {
            return ptr;
        }
        return nullptr;
    };

    m_chip_factories["Eeprom"] = [](mc::mutable_dict& csr_data) -> std::shared_ptr<chip_base> {
        auto ptr = std::make_shared<chip_eeprom>();
        if (ptr && ptr->init(csr_data)) {
            return ptr;
        }
        return nullptr;
    };

    // 注册bus工厂函数
    m_bus_factories["I2c"] = [](mc::mutable_dict& csr_data) -> std::shared_ptr<bus_base> {
        auto ptr = std::make_shared<bus_i2c>();
        if (ptr && ptr->init(csr_data)) {
            return ptr;
        }
        return nullptr;
    };

    m_bus_factories["Hisport"] = [](mc::mutable_dict& csr_data) -> std::shared_ptr<bus_base> {
        auto ptr = std::make_shared<bus_hisport>();
        if (ptr && ptr->init(csr_data)) {
            return ptr;
        }
        return nullptr;
    };

    m_bus_factories["I2cMux"] = [](mc::mutable_dict& csr_data) -> std::shared_ptr<bus_base> {
        auto ptr = std::make_shared<bus_i2c_mux>();
        if (ptr && ptr->init(csr_data)) {
            return ptr;
        }
        return nullptr;
    };
}

std::shared_ptr<chip_base> device_manager::create_chip(const std::string& object_name,
                                                       const std::string& class_name,
                                                       mc::mutable_dict&  csr_data) {
    std::lock_guard<std::mutex> lock(m_mutex);
    try {
        if (csr_data.empty()) {
            MC_THROW(mc::invalid_op_exception, "csr_data is empty");
        }
        // 检查对象是否已存在
        if (m_chip_table.find(object_name) != m_chip_table.end()) {
            return m_chip_table[object_name];
        }

        // 查找对应的工厂函数
        auto factory_it = m_chip_factories.find(class_name);
        if (factory_it == m_chip_factories.end()) {
            elog("Unsupported chip type: ${type}", ("type", class_name));
            return nullptr;
        }

        // 使用工厂函数创建对象
        auto chip_ptr = factory_it->second(csr_data);
        if (chip_ptr) {
            m_chip_table[object_name] = chip_ptr;
            return chip_ptr;
        } else {
            elog("Failed to create chip object: ${name}, type: ${type}",
                 ("name", object_name)("type", class_name));
            return nullptr;
        }
    } catch (const std::exception& e) {
        elog("Exception creating chip object: ${name}, error: ${error}", ("name", object_name)("error", e.what()));
        return nullptr;
    }
}

std::shared_ptr<bus_base> device_manager::create_bus(const std::string& object_name,
                                                     const std::string& class_name,
                                                     mc::mutable_dict&  csr_data) {
    std::lock_guard<std::mutex> lock(m_mutex);
    try {
        if (csr_data.empty()) {
            MC_THROW(mc::invalid_op_exception, "csr_data is empty");
        }
        // 检查对象是否已存在
        if (m_bus_table.find(object_name) != m_bus_table.end()) {
            return m_bus_table[object_name];
        }

        // 查找对应的工厂函数
        auto factory_it = m_bus_factories.find(class_name);
        if (factory_it == m_bus_factories.end()) {
            elog("Unsupported bus type: ${type}", ("type", class_name));
            return nullptr;
        }

        // 使用工厂函数创建对象
        auto bus_ptr = factory_it->second(csr_data);
        if (bus_ptr) {
            m_bus_table[object_name] = bus_ptr;
            return bus_ptr;
        } else {
            elog("Failed to create bus object: ${name}, type: ${type}",
                 ("name", object_name)("type", class_name));
            return nullptr;
        }
    } catch (const std::exception& e) {
        elog("Exception creating bus object: ${name}, error: ${error}", ("name", object_name)("error", e.what()));
        return nullptr;
    }
}

std::variant<std::shared_ptr<chip_base>, std::shared_ptr<bus_base>>
device_manager::find_object(const std::string& name, object_type type) {
    std::lock_guard<std::mutex> lock(m_mutex);
    try {
        switch (type) {
        case object_type::chip: {
            auto it = m_chip_table.find(name);
            if (it != m_chip_table.end()) {
                return it->second;
            }
            break;
        }
        case object_type::bus: {
            auto it = m_bus_table.find(name);
            if (it != m_bus_table.end()) {
                return it->second;
            }
            break;
        }
        default:
            elog("Unsupported object type: ${type}", ("type", static_cast<int>(type)));
            break;
        }

        dlog("Object not found: ${name}, type: ${type}", ("name", name)("type", static_cast<int>(type)));
        return std::shared_ptr<chip_base>(nullptr); // 返回空的shared_ptr作为默认值
    } catch (const std::exception& e) {
        elog("Exception finding object: ${name}, error: ${error}", ("name", name)("error", e.what()));
        return std::shared_ptr<chip_base>(nullptr);
    }
}

bool device_manager::remove_object(const std::string& name, object_type type) {
    std::lock_guard<std::mutex> lock(m_mutex);
    try {
        switch (type) {
        case object_type::chip: {
            auto it = m_chip_table.find(name);
            if (it != m_chip_table.end()) {
                m_chip_table.erase(it);
                return true;
            }
            break;
        }
        case object_type::bus: {
            auto it = m_bus_table.find(name);
            if (it != m_bus_table.end()) {
                m_bus_table.erase(it);
                return true;
            }
            break;
        }
        default:
            elog("Unsupported object type: ${type}", ("type", static_cast<int>(type)));
            return false;
        }

        wlog("Object to be deleted does not exist: ${name}, type: ${type}",
             ("name", name)("type", static_cast<int>(type)));
        return false;
    } catch (const std::exception& e) {
        elog("Exception deleting object: ${name}, error: ${error}", ("name", name)("error", e.what()));
        return false;
    }
}

void device_manager::clear_all() {
    std::lock_guard<std::mutex> lock(m_mutex);
    try {
        size_t chip_count = m_chip_table.size();
        size_t bus_count  = m_bus_table.size();

        m_chip_table.clear();
        m_bus_table.clear();

        dlog("Cleared all object tables, deleted ${chip_count} chip objects, ${bus_count} bus objects",
             ("chip_count", chip_count)("bus_count", bus_count));
    } catch (const std::exception& e) {
        elog("Exception clearing object tables: ${error}", ("error", e.what()));
    }
}

} // namespace dev